package com.qingfeng.medical.biz.information.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qingfeng.medical.base.handler.GeneralAuthException;
import com.qingfeng.medical.base.result.ResultCodeEnum;
import com.qingfeng.medical.biz.auth.dao.SysRoleMapper;
import com.qingfeng.medical.biz.auth.dao.SysUserRoleMapper;
import com.qingfeng.medical.biz.auth.domain.entity.SysRole;
import com.qingfeng.medical.biz.auth.domain.entity.SysUser;
import com.qingfeng.medical.biz.auth.domain.entity.SysUserRole;
import com.qingfeng.medical.biz.auth.domain.enums.RoleEnums;
import com.qingfeng.medical.biz.auth.service.SysUserService;
import com.qingfeng.medical.biz.information.dao.DoctorInfoMapper;
import com.qingfeng.medical.biz.hosp.dao.HospDepartmentMapper;
import com.qingfeng.medical.biz.information.domain.entity.DoctorInfo;
import com.qingfeng.medical.biz.hosp.domain.entity.HospDepartment;
import com.qingfeng.medical.biz.information.domain.enums.DoctorPositionEnum;
import com.qingfeng.medical.biz.information.domain.ro.DoctorInfoRo;
import com.qingfeng.medical.biz.information.domain.vo.DoctorInfoVo;
import com.qingfeng.medical.biz.information.service.DoctorInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 医师信息表
 *
 * @author 清风学Java
 * @date 2023-04-08 23:43:31
 */
@Service
public class DoctorInfoServiceImpl extends ServiceImpl<DoctorInfoMapper, DoctorInfo> implements DoctorInfoService {

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private HospDepartmentMapper hospDepartmentMapper;

    /**
     * 同步医师信息
     */
    @Override
    public void refreshDoctorInfo() {
        // 同步的是赢添加了的用户，但是详细信息还没有同步的
        SysRole sysRole = sysRoleMapper.selectOne(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getRoleCode, RoleEnums.GENERAL_PHYSICIAN));
        Optional.ofNullable(sysRole)
                .ifPresent(s -> {
                            // 根据角色查询用户Id
                            List<SysUserRole> sysUserRoles = sysUserRoleMapper.selectList(
                                    new LambdaQueryWrapper<SysUserRole>()
                                            .eq(SysUserRole::getRoleId, s.getId())
                            );

                            if (CollUtil.isNotEmpty(sysUserRoles)) {
                                // 过滤出用户Id
                                List<Long> userIds = sysUserRoles.stream()
                                        .map(SysUserRole::getUserId)
                                        .collect(Collectors.toList());

                                // 查询已同步的信息
                                List<DoctorInfo> doctorInfos = baseMapper.selectList(
                                        new LambdaQueryWrapper<DoctorInfo>()
                                                .in(DoctorInfo::getUserId, userIds)
                                );

                                List<Long> ids;
                                if (CollUtil.isNotEmpty(doctorInfos)) {
                                    Set<Long> userSet = doctorInfos.stream()
                                            .map(DoctorInfo::getUserId)
                                            .collect(Collectors.toSet());
                                    ids = userIds.stream()
                                            .filter(userId -> !userSet.contains(userId))
                                            .collect(Collectors.toList());
                                } else {
                                    ids = userIds;
                                }

                                if (CollUtil.isNotEmpty(ids)) {
                                    // 说明存在还未更新的用户
                                    this.saveBatch(
                                            ids.stream()
                                                    .map(id -> DoctorInfo.builder()
                                                            .userId(id)
                                                            .build()
                                                    )
                                                    .collect(Collectors.toList())
                                    );
                                }
                            }
                        }
                );
    }

    /**
     * 查询医师信息
     *
     * @param page
     * @param limit
     * @param username
     * @param position
     * @return
     */
    @Override
    public DoctorInfoVo findDoctorInfo(Long page, Long limit, String username, DoctorPositionEnum position) {
        try {
            // 先查询医师用户基础信息
            IPage<SysUser> pageModel = sysUserService.selectUserPage(
                    new Page<SysUser>(page, limit),
                    username,
                    position
            );

            if (pageModel.getTotal() == 0) {
                return DoctorInfoVo.builder()
                        .total(0L)
                        .pageNo(page)
                        .pageSize(limit)
                        .doctorInfoRos(Collections.emptyList())
                        .build();
            }
            List<SysUser> records = pageModel.getRecords();

            // 根据用户Id查新医师详情
            List<DoctorInfo> doctorInfos = baseMapper.selectList(
                    new LambdaQueryWrapper<DoctorInfo>()
                            .in(DoctorInfo::getUserId, records.stream()
                                    .map(SysUser::getId)
                                    .collect(Collectors.toList()))
            );
            Map<Long, DoctorInfo> doctorInfoMap = doctorInfos
                    .stream()
                    .collect(Collectors.toMap(
                            DoctorInfo::getUserId,
                            Function.identity()
                    ));

            List<List<Long>> ids = doctorInfos
                    .stream()
                    .filter(d -> CollUtil.isNotEmpty(d.getDepartmentPatient()))
                    .map(d -> d.getDepartmentPatient()
                            .stream()
                            .flatMap(Collection::stream)
                            .filter(id -> id != 0L)
                            .collect(Collectors.toList())
                    )
                    .collect(Collectors.toList());

            List<HospDepartment> hospDepartmentList = Collections.emptyList();
            if (CollUtil.isNotEmpty(ids)){
                hospDepartmentList = hospDepartmentMapper.selectList(
                                new LambdaQueryWrapper<HospDepartment>()
                                        .in(HospDepartment::getId,ids
                                                .stream()
                                                .flatMap(Collection::stream)
                                                .distinct()
                                                .collect(Collectors.toList())
                                        )
                        ).stream()
                        .collect(Collectors.toList());
            }

            List<HospDepartment> finalHospDepartmentList = hospDepartmentList;
            List<DoctorInfoRo> doctorInfoRos = records.stream()
                    .map(u -> {
                        DoctorInfo doctorInfo = doctorInfoMap.get(u.getId());
                        DoctorInfoRo doctorInfoRo = DoctorInfoRo.builder()
                                .username(u.getUsername())
                                .name(u.getName())
                                .phone(u.getPhone())
                                .headUrl(u.getHeadUrl())
                                .status(u.getStatus())
                                .build();

                        Optional.ofNullable(doctorInfo)
                                .ifPresent(d -> {
                                    doctorInfoRo.setId(d.getId());
                                    doctorInfoRo.setPosition(d.getPosition());
                                    doctorInfoRo.setIntroduction(d.getIntroduction());
                                    doctorInfoRo.setDepartmentPatient(
                                            CollUtil.isEmpty(d.getDepartmentPatient()) ?
                                                    "":
                                            finalHospDepartmentList.stream()
                                                    .filter(h -> d.getDepartmentPatient()
                                                            .stream()
                                                            .flatMap(Collection::stream)
                                                            .filter(id -> id != 0L)
                                                            .collect(Collectors.toSet()).contains(h.getId())
                                                    )
                                                    .map(h -> h.getDepName() + "->" + h.getPatientName())
                                                    .collect(Collectors.joining(",\r\n"))
                                    );
                                    doctorInfoRo.setWeekday(
                                      CollUtil.isEmpty(d.getWeekday()) ?
                                      "" : d.getWeekday()
                                              .stream()
                                              .collect(Collectors.joining("、"))
                                    );
                                });

                        return doctorInfoRo;
                    })
                    .collect(Collectors.toList());

            return DoctorInfoVo.builder()
                    .total(pageModel.getTotal())
                    .pageNo(pageModel.getPages())
                    .pageSize(pageModel.getSize())
                    .doctorInfoRos(doctorInfoRos)
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
            throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "请先同步医师信息");
        }

    }
}